home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / gems / g_gemsi.lha / GraphicsGems / PolyScan / poly_scan.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-10  |  4.6 KB  |  182 lines

  1. /*
  2. Generic Convex Polygon Scan Conversion and Clipping
  3. by Paul Heckbert
  4. from "Graphics Gems", Academic Press, 1990
  5. */
  6.  
  7. /*
  8.  * poly_scan.c: point-sampled scan conversion of convex polygons
  9.  *
  10.  * Paul Heckbert    1985, Dec 1989
  11.  */
  12.  
  13. #include <stdio.h>
  14. #include <math.h>
  15. #include "poly.h"
  16.  
  17. /*
  18.  * poly_scan: Scan convert a polygon, calling pixelproc at 
  19.  * each pixel with an interpolated Poly_vert structure.
  20.  *   Polygon can be clockwise or ccw.
  21.  * Polygon is clipped in 2-D to win, the screen space window.
  22.  *
  23.  * Scan conversion is done on the basis of Poly_vert fields sx and sy.
  24.  * These two must always be interpolated, and only they have 
  25.  * special meaning to this code; any other fields are 
  26.  * blindly interpolated regardless of their semantics.
  27.  *
  28.  * The pixelproc subroutine takes the arguments:
  29.  *
  30.  *    pixelproc(x, y, point)
  31.  *    int x, y;
  32.  *    Poly_vert *point;
  33.  *
  34.  * All the fields of point indicated by p->mask will be 
  35.  * valid inside pixelproc except sx and sy.
  36.  * If they were computed, they would have values
  37.  * sx=x+.5 and sy=y+.5, since sampling is done at pixel centers.
  38.  */
  39.  
  40. void poly_scan(p, win, pixelproc)
  41. register Poly *p;        /* polygon */
  42. Window *win;            /* 2-D screen space clipping window */
  43. void (*pixelproc)();        /* procedure called at each pixel */
  44. {
  45.     register int i, li, ri, y, ly, ry, top, rem, mask;
  46.     double ymin;
  47.     Poly_vert l, r, dl, dr;
  48.  
  49.     if (p->n>POLY_NMAX) {
  50.         fprintf(stderr, "poly_scan: too many vertices: %d\n", p->n);
  51.         return;
  52.     }
  53.  
  54.  
  55.     ymin = HUGE;
  56.     for (i=0; i<p->n; i++)    /* find top vertex (y points down) */
  57.         if (p->vert[i].sy < ymin) {
  58.             ymin = p->vert[i].sy;
  59.             top = i;
  60.         }
  61.  
  62.     li = ri = top;            /* left and right vertex indices */
  63.     rem = p->n;                /* number of vertices remaining */
  64.     y = ceil(ymin-.5);            /* current scan line */
  65.     ly = ry = y-1;            /* lower end of left & right edges */
  66.     mask = p->mask & ~POLY_MASK(sy); /* stop interpolating screen y */
  67.  
  68.     while (rem>0) { /* scan in y, activating new edges on left & */                  /* right as scan line passes over new vertices */
  69.  
  70.         while (ly<=y && rem>0) {    /* advance left edge? */
  71.             rem--;
  72.             i = li-1;            /* step ccw down left side */
  73.             if (i<0) i = p->n-1;
  74.             incrementalize_y(&p->vert[li], &p->vert[i], &l,
  75.                          &dl, y, mask);
  76.             ly = floor(p->vert[i].sy+.5);
  77.             li = i;
  78.         }
  79.         while (ry<=y && rem>0) {    /* advance right edge? */
  80.             rem--;
  81.             i = ri+1;            /* step cw down right edge */
  82.             if (i>=p->n) i = 0;
  83.             incrementalize_y(&p->vert[ri], &p->vert[i], &r,
  84.                          &dr, y, mask);
  85.             ry = floor(p->vert[i].sy+.5);
  86.             ri = i;
  87.         }
  88.  
  89.         while (y<ly && y<ry)  {
  90.                     /* do scanlines till end of l or r edge */
  91.             if (y>=win->y0 && y<=win->y1)
  92.               if (l.sx<=r.sx) scanline(y, &l, &r, win, pixelproc, mask);
  93.               else           scanline(y, &r, &l, win, pixelproc, mask);
  94.             y++;
  95.             increment(&l, &dl, mask);
  96.             increment(&r, &dr, mask);
  97.         }
  98.     }
  99. }
  100.  
  101.  
  102. /* scanline: output scanline by sampling polygon at Y=y+.5 */
  103.  
  104. static scanline(y, l, r, win, pixelproc, mask)
  105. int y, mask;
  106. Poly_vert *l, *r;
  107. Window *win;
  108. void (*pixelproc)();
  109. {
  110.     int x, lx, rx;
  111.     Poly_vert p, dp;
  112.  
  113.     mask &= ~POLY_MASK(sx);        /* stop interpolating screen x */
  114.     lx = ceil(l->sx-.5);
  115.     if (lx<win->x0) lx = win->x0;
  116.     rx = floor(r->sx-.5);
  117.     if (rx>win->x1) rx = win->x1;
  118.     if (lx>rx) return;
  119.     incrementalize_x(l, r, &p, &dp, lx, mask);
  120.     for (x=lx; x<=rx; x++) {        /* scan in x, generating pixels */
  121.         (*pixelproc)(x, y, &p);
  122.         increment(&p, &dp, mask);
  123.     }
  124. }
  125.  
  126. /*
  127.  * incrementalize_y: put intersection of line Y=y+.5 with edge  
  128.  * between points p1 and p2 in p, put change with respect to y in dp  
  129.  */
  130.  
  131. static incrementalize_y(p1, p2, p, dp, y, mask)
  132. register double *p1, *p2, *p, *dp;
  133. register int mask;
  134. int y;
  135. {
  136.     double dy, frac;
  137.  
  138.     dy = ((Poly_vert *)p2)->sy - ((Poly_vert *)p1)->sy;
  139.     if (dy==0.) dy = 1.;
  140.     frac = y+.5 - ((Poly_vert *)p1)->sy;
  141.  
  142.     for (; mask!=0; mask>>=1, p1++, p2++, p++, dp++)
  143.         if (mask&1) {
  144.             *dp = (*p2-*p1)/dy;
  145.             *p = *p1+*dp*frac;
  146.         }
  147. }
  148.  
  149.  
  150. /*
  151.  * incrementalize_x: put intersection of line X=x+.5 with 
  152.  * edge between points p1 and p2 in p,
  153.  *  put change with respect to x in dp
  154.  */
  155.  
  156. static incrementalize_x(p1, p2, p, dp, x, mask)
  157. register double *p1, *p2, *p, *dp;
  158. register int mask;
  159. int x;
  160. {
  161.     double dx, frac;
  162.  
  163.     dx = ((Poly_vert *)p2)->sx - ((Poly_vert *)p1)->sx;
  164.     if (dx==0.) dx = 1.;
  165.     frac = x+.5 - ((Poly_vert *)p1)->sx;
  166.  
  167.     for (; mask!=0; mask>>=1, p1++, p2++, p++, dp++)
  168.         if (mask&1) {
  169.             *dp = (*p2-*p1)/dx;
  170.             *p = *p1+*dp*frac;
  171.         }
  172. }
  173.  
  174. static increment(p, dp, mask)
  175. register double *p, *dp;
  176. register int mask;
  177. {
  178.     for (; mask!=0; mask>>=1, p++, dp++)
  179.         if (mask&1)
  180.             *p += *dp;
  181. }
  182.